#!/usr/bin/env python3
# This module requires python-telegram-bot
import os
import sys
import logging
import configparser
import argparse

# 需要提前安装好telegram组件
# todo 该组件的作用
try:
    import telegram.ext
except ImportError:
    print("You need python-telegram-bot package installed to start the bot")
    sys.exit()

from libbots import data, model, utils

import torch

# 配置telegram 开放接口的appkey和appsecret
# Configuration file with the following contents
# [telegram]
# api=API_KEY
CONFIG_DEFAULT = "~/.config/rl_ch12_bot.ini"

log = logging.getLogger("telegram")


if __name__ == "__main__":
    logging.basicConfig(format="%(asctime)-15s %(levelname)s %(message)s", level=logging.INFO)
    parser = argparse.ArgumentParser()
    # telegram配置文件的路径
    parser.add_argument("--config", default=CONFIG_DEFAULT,
                        help="Configuration file for the bot, default=" + CONFIG_DEFAULT)
    parser.add_argument("-m", "--model", required=True, help="Model to load")
    # todo 参数含义
    parser.add_argument("--sample", default=False, action='store_true', help="Enable sampling mode")
    prog_args = parser.parse_args()

    # 用来读取配置文件ini的工具类
    conf = configparser.ConfigParser()
    if not conf.read(os.path.expanduser(prog_args.config)):
        log.error("Configuration file %s not found", prog_args.config)
        sys.exit()

    # 加载模型单词token字典，之前存储到本地的词典实在这边有使用
    emb_dict = data.load_emb_dict(os.path.dirname(prog_args.model))
    log.info("Loaded embedded dict with %d entries", len(emb_dict))
    # 构建一个从id到单词的字典
    rev_emb_dict = {idx: word for word, idx in emb_dict.items()}
    # 获取结束单词的token
    end_token = emb_dict[data.END_TOKEN]

    # 加载短语模型
    net = model.PhraseModel(emb_size=model.EMBEDDING_DIM, dict_size=len(emb_dict), hid_size=model.HIDDEN_STATE_SIZE)
    net.load_state_dict(torch.load(prog_args.model))

    def bot_func(bot, update, args):
        '''
        args 这个应该是将用户输入的一句话分割为独立的单词列表
        '''
        text = " ".join(args) # 将单词列表转换为字符串列表
        # 重新分割为单词列表
        words = utils.tokenize(text)
        # 按照单词表重新序列化为token id 列表
        seq_1 = data.encode_words(words, emb_dict)
        # 将token id 序列打包为LSTM 压缩 词向量序列
        input_seq = model.pack_input(seq_1, net.emb)
        # 编码得到编码隐藏层信息
        enc = net.encode(input_seq)
        # 判断是采用根据概率得到应答还是采用最大概率得到应答对话
        if prog_args.sample:
            _, tokens = net.decode_chain_sampling(enc, input_seq.data[0:1], seq_len=data.MAX_TOKENS,
                                                  stop_at_token=end_token)
        else:
            _, tokens = net.decode_chain_argmax(enc, input_seq.data[0:1], seq_len=data.MAX_TOKENS,
                                                stop_at_token=end_token)
        # 如果最后一个字符是结束字符，则去除最后一个字符
        if tokens[-1] == end_token:
            tokens = tokens[:-1]
        # 将应答的token id序列转换为单词序列
        reply = data.decode_words(tokens, rev_emb_dict)
        if reply:
            # 生成字符串后返回给机器人
            reply_text = utils.untokenize(reply)
            bot.send_message(chat_id=update.message.chat_id, text=reply_text)

    # telegram配置访问api
    updater = telegram.ext.Updater(conf['telegram']['api'])
    # telegram配置应答方法
    updater.dispatcher.add_handler(telegram.ext.CommandHandler('bot', bot_func, pass_args=True))

    log.info("Bot initialized, started serving")
    # 运行telegram机器人
    updater.start_polling()
    updater.idle()

    pass
